package Merlion.SCM.bean;

import Merlion.CRM.entity.PricebookEntity;
import Merlion.MRP.entity.BillOfMaterialsEntity;
import Merlion.MRP.entity.BillOfMaterialsEntryEntity;
import Merlion.MRP.entity.IndividualWeeklyMaterialRequirementEntity;
import Merlion.SCM.entity.InventoryBatchEntity;
import Merlion.util.state.InventoryState;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.Query;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import Merlion.SCM.entity.MaterialEntity;
import Merlion.SCM.entity.ProductEntity;
import Merlion.SCM.entity.WarehouseEntity;
import Merlion.util.state.WarehouseState;
import javax.persistence.NoResultException;

@Stateless
public class InventoryItemsBean implements InventoryItemsBeanRemote {

    @PersistenceContext
    EntityManager em;
    String message;

    @Override
    public long addWarehouse(String name, int capacity, String street, String city, String country, String postcode) {
        System.out.println("**InventoryItemsBean: addWarehouse()");

        String returnIdString = "0";
        Long returnId = Long.parseLong(returnIdString);

        System.out.println("addWarehouse");
        System.out.println("Searching for duplicate warehouse data");
        Query q = em.createQuery("Select a from WarehouseEntity a");

        boolean duplicate = false;
        for (Object o : q.getResultList()) {
            WarehouseEntity c = (WarehouseEntity) o;
            if (c.getName().equals(name)) {
                duplicate = true;
                break;
            }
        }

        if (!duplicate) {
            System.out.println("Duplicate not found");
            WarehouseEntity warehouse = new WarehouseEntity(name, street, city, country, postcode, capacity);

            em.persist(warehouse);
            em.flush();
            System.out.print("Warehouse persisted");

            returnId = warehouse.getId();
            System.out.println("Warehouse id is : " + returnId);
        }

        System.out.println("Return id is : " + returnId);
        return returnId;
    }

    @Override
    public void deleteWarehouse(Long id) {
        System.out.println("**InventoryItemsBean: deleteWarehouse()");

        WarehouseEntity warehouse = em.find(WarehouseEntity.class, id);
        System.out.println("Warehouse ID is : " + id);
        if (warehouse != null && !warehouse.isDeleted()) {
            System.out.println("Warehouse data found");
            warehouse.setDeleted(true);
            em.flush();
            System.out.println("Warehouse data deleted");
        } else {
            System.out.println("No warehouse data found. Delete warehouse failed.");
        }
    }

    @Override
    public void editWarehouse(Long id, String name, String street, String city, String country, String postcode) {
        System.out.println("**InventoryItemsBean: editWarehouse()");

        WarehouseEntity warehouse = em.find(WarehouseEntity.class, id);

        if (warehouse != null && !warehouse.isDeleted()) {
            System.out.println("Warehouse data found");
            warehouse.setName(name);
            warehouse.setStreet(street);
            warehouse.setCity(city);
            warehouse.setCountry(country);
            warehouse.setPostcode(postcode);

            em.flush();
            System.out.println("Warehouse data edited.");
        } else {
            System.out.println("No data about warehouse found. Edit warehouse failed.");
        }
    }

    @Override
    public List<WarehouseState> viewWarehouse() {
        System.out.println("**InventoryItemsBean: viewWarehouse()");

        Query q = em.createQuery("SELECT c FROM WarehouseEntity c");
        List stateList = new ArrayList();

        for (Object o : q.getResultList()) {
            WarehouseEntity c = (WarehouseEntity) o;
            if (!c.isDeleted()) {

                //    System.out.println(c.getSalutation());
                WarehouseState wState = new WarehouseState(c.getId(), c.getCapacity(), c.getName(), c.getStreet(), c.getCity(), c.getCountry(), c.getPostcode());
                wState.setId(c.getId());
                wState.setName(c.getName());
                wState.setStreet(c.getStreet());
                wState.setCity(c.getCity());
                wState.setCountry(c.getCountry());
                wState.setPostcode(c.getPostcode());

                stateList.add(wState);
            }
        }
        return stateList;
    }

    @Override
    public boolean createMaterial(String name, String description, int leadTime, int shelfLife, int lotSize, String lotSizeUnit) {
        System.out.println("**InventoryItemsBean: createMaterial()");

        Long id = this.searchMaterialId(name);

        if (id != null) {
            this.updateMaterial(id, name, description, leadTime, lotSize, leadTime, shelfLife, lotSize, lotSizeUnit);
            em.flush();
            return true;
        }

        MaterialEntity me = new MaterialEntity(name, description, leadTime, shelfLife, lotSize, lotSizeUnit);

        me.setInHandQty(0);
        me.setReservedQty(0);
        me.setOrderedQty(0); // this is planned receipt
        em.persist(me);
        em.flush();

        return true;
    }

    @Override
    public boolean updateMaterial(Long id, String name, String description, int inHandQty, int committedQty, int leadTime, int shelfLife, int lotSize, String lotSizeUnit) {
        System.out.println("**InventoryItemsBean: updateMaterial()");

        MaterialEntity me = em.find(MaterialEntity.class, id);

        if (me == null) {
            return false;
        }

        me.setName(name);
        me.setDescription(description);
        me.setOrderedQty(inHandQty);
        me.setReservedQty(committedQty);
        me.setLeadTime(leadTime);
        me.setLeadTime(leadTime);
        me.setShelfLife(shelfLife);
        me.setLotSize(lotSize);
        me.setLotSizeUnit(lotSizeUnit);
        em.flush();

        return true;
    }

    public boolean deleteMaterial(Long id) {
        System.out.println("**InventoryItemsBean: deleteMaterial()");

        MaterialEntity me = em.find(MaterialEntity.class, id);

        Query q1 = em.createQuery("select a from InventoryBatchEntity a where a.itemId = :id");
        q1.setParameter("id", id);
        
        Query q2 = em.createQuery("select a from BillOfMaterialsEntryEntity a");
        
        Query q3 = em.createQuery("select a from IndividualWeeklyMaterialRequirementEntity a");
        
        List<InventoryBatchEntity> l1 = (List<InventoryBatchEntity>) q1.getResultList();
        List<BillOfMaterialsEntryEntity> l2 = new ArrayList();
        for (Object o: q2.getResultList()) {
            BillOfMaterialsEntryEntity l2e = (BillOfMaterialsEntryEntity) o;
            if (l2e.getIngredient().equals(me)) 
                l2.add(l2e);
        } 
        
        List<IndividualWeeklyMaterialRequirementEntity> l3 = new ArrayList();
        for (Object o : l3) {
            IndividualWeeklyMaterialRequirementEntity l3e = (IndividualWeeklyMaterialRequirementEntity) o;
            if (l3e.getMaterial().equals(me)) {
                l3.add(l3e);
            }
        }
        
        if (me == null) {
            return false;
        } else if (!(l1.isEmpty() && l2.isEmpty() && l3.isEmpty())) {
            return false;
        } else {
            em.remove(me);
            em.flush();
            return true;
        }
    }

    @Override
    public boolean createProduct(String name, String description, int shelfLife, double caseWeight, double basePrice, int productionRate) {
        System.out.println("**InventoryItemsBean: createProduct()");

        double limitPrice = 0;
        double listPrice = 0;

        Long id = this.searchProductId(name);
        if (id != null) {
            this.updateProduct(id, name, description,
                    shelfLife, caseWeight,
                    basePrice, limitPrice, listPrice, productionRate);

            ProductEntity product = em.find(ProductEntity.class, id);

            BillOfMaterialsEntity bom = product.getBOMEntity();
            if (bom == null) {
                bom = new BillOfMaterialsEntity(product);
                em.persist(bom);
            }

            em.flush();
            return true;
        }

        ProductEntity pe = new ProductEntity(name, description, shelfLife, caseWeight, basePrice, productionRate);
        em.persist(pe);
        BillOfMaterialsEntity bom = new BillOfMaterialsEntity(pe);
        em.persist(bom);
        em.flush();

        return true;
    }

    @Override
    public Long createProduct2(String name, String description, int shelfLife, double caseWeight,
            double basePrice, int productionRate, double listPrice, double limitPrice) {

        System.out.println("**InventoryItemsBean: createProduct2()");

        Long id = this.searchProductId(name);

        if (id != null) {
            System.out.println("Product already exist, updating record");
            this.updateProduct(id, name, description,
                    shelfLife, caseWeight,
                    basePrice, limitPrice, listPrice, productionRate);
            ProductEntity product = em.find(ProductEntity.class, id);
            em.flush();

            return id;
        }

        System.out.println("Creating new product");
        ProductEntity product = new ProductEntity(name, description, shelfLife, caseWeight, basePrice, productionRate, listPrice, limitPrice);
        em.persist(product);
        Long productId = product.getId();

        return productId;
    }

    @Override
    public void setPriceBook(List<PricebookEntity> pricebook, Long productId) {
        System.out.println("**InventoryItemsBean: setPriceBook()");

        ProductEntity product = em.find(ProductEntity.class, productId);
        product.setPricebook(pricebook);
        em.flush();
    }

    @Override
    public boolean updateProduct(Long id, String name, String description,
            int shelfLife, double caseWeight,
            double basePrice, double limitPrice, double listPrice, int productionRate) {
        System.out.println("**InventoryItemsBean: updateProduct()");

        ProductEntity pe = em.find(ProductEntity.class, id);

        if (pe == null) {
            return false;
        }

        pe.setName(name);
        pe.setDescription(description);
        pe.setShelfLife(shelfLife);
        pe.setCaseWeight(caseWeight);
        pe.setBasePrice(basePrice);
        pe.setProductionRate(productionRate);
        pe.setLimitPrice(limitPrice);
        pe.setListPrice(listPrice);
        em.flush();

        return true;
    }

    @Override
    public boolean deleteProduct(Long id) {
        System.out.println("**InventoryItemsBean: deleteProduct()");

        ProductEntity pe = em.find(ProductEntity.class, id);

        if (pe == null) {
            return false;
        }

        if (!pe.getProductBatches().isEmpty()) {

            em.remove(pe);
            em.flush();

        }
        return true;
    }

    @Override
    public List<InventoryState> viewMaterials() {
        System.out.println("**InventoryItemsBean: viewMaterials()");

        Query q = em.createQuery("SELECT m FROM MaterialEntity m");
        List stateList = new ArrayList();

        for (Object o : q.getResultList()) {
            MaterialEntity me = (MaterialEntity) o;
            InventoryState invState = new InventoryState();
            invState.createMaterialState(me.getId(), me.getName(), me.getDescription(), me.getInHandQty(),
                    me.getReservedQty(), me.getShelfLife(), me.getInventoryType(), me.getLeadTime(), me.getLotSize(), me.getLotSizeUnit());
            stateList.add(invState);
        }

        return stateList;
    }

    @Override
    public List<InventoryState> viewProducts() {
        System.out.println("**InventoryItemsBean: viewProducts()");

        Query q = em.createQuery("SELECT p FROM ProductEntity p");
        List stateList = new ArrayList();

        for (Object o : q.getResultList()) {
            ProductEntity pe = (ProductEntity) o;
            List<Long> batchIds = new ArrayList();

            for (InventoryBatchEntity batch : pe.getProductBatches()) {
                batchIds.add(batch.getId());
            }

            InventoryState invState = new InventoryState();
            invState.createProductState(pe.getId(), pe.getName(), pe.getDescription(), pe.getInHandQty(),
                    pe.getReservedQty(), pe.getShelfLife(), pe.getInventoryType(), pe.getCaseWeight(), pe.getBasePrice(), pe.getProductionRate(), batchIds);//, pe.getProductionRate());
            invState.setLimitPrice(pe.getLimitPrice());
            invState.setListPrice(pe.getListPrice());
            
            stateList.add(invState);
        }

        return stateList;
    }

    @Override
    public ProductEntity searchProduct(Long id) {
        System.out.println("**InventoryItemsBean: searchProduct()");

        try {
            Query q = em.createQuery("SELECT a from ProductEntity a WHERE a.id=:id").setParameter("id", id);
            ProductEntity product = (ProductEntity) q.getSingleResult();

            return product;
        } catch (NoResultException e) {
            return null;
        }
    }

    @Override
    public MaterialEntity searchMaterial(Long id) {
        System.out.println("**InventoryItemsBean: searchMaterial()");

        try {
            Query q = em.createQuery("SELECT a from MaterialEntity a WHERE a.id=:id").setParameter("id", id);
            MaterialEntity material = (MaterialEntity) q.getSingleResult();

            return material;
        } catch (NoResultException e) {
            return null;
        }
    }

    @Override
    public Long searchMaterialId(String name) {
        System.out.println("**InventoryItemsBean: searchMaterialId()");

        Query q = em.createQuery("Select a FROM MaterialEntity a WHERE a.name=:name").setParameter("name", name);
        try {
            MaterialEntity material = (MaterialEntity) q.getSingleResult();
            return material.getId();
        } catch (NoResultException e) {
            return null;
        }
    }

    @Override
    public Long searchProductId(String name) {
        System.out.println("**InventoryItemsBean: searchProductId()");

        Query q = em.createQuery("Select a FROM ProductEntity a WHERE a.name=:name").setParameter("name", name);
        try {
            ProductEntity product = (ProductEntity) q.getSingleResult();
            return product.getId();
        } catch (NoResultException e) {
            return null;
        }
    }
}
